package com.leon.learnenginespace.drools.support;

import com.leon.learnenginespace.drools.bl.GeneralRulesBL;
import com.leon.learnenginespace.drools.dao.GeneralRulesMapper;
import com.leon.learnenginespace.drools.pojo.TDrlNSceneRuleBindConfig;
import com.leon.learnenginespace.drools.pojo.TDrlNversion;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.kie.api.KieBase;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.StatelessKieSession;
import org.kie.internal.utils.KieHelper;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @description: 规则中心规则加载器
 * @author: WT
 * @date: 2024/3/31 18:22
 * @Version 1.0
 **/
@Slf4j
@Component
public class DroolsCenterFrameworkHelper {
    private final ConcurrentMap<String, KieBase> kieBaseConcurrentMap = new ConcurrentHashMap<>();
    /**
     * 规则版本 Map
     * 只有在此 Map 中的规则类型才会加载（初始版本为0）
     */
    public static Map<String, String> VERSION_MAP = new HashMap<>();
    @Resource
    private GeneralRulesMapper generalRulesMapper;
    @Resource
    GeneralRulesBL generalRulesBL;

    @Scheduled(fixedDelay = 60000)
    public void autoRefresh() {
        List<TDrlNversion> nowVersion = null;
        try {
            nowVersion = generalRulesMapper.selectVersion();
        } catch (Exception e) {
            log.error("规则加载异常：版本查询失败！", e);
        }
        if (CollectionUtils.isEmpty(nowVersion)) {
            log.error("规则加载异常：规则版本为空！");
            return;
        }
        for (TDrlNversion tDrlNversion : nowVersion) {
            String module = tDrlNversion.getModule();
            if (StringUtils.isBlank(module)) {
                log.info("规则模块[ " + module + " ]为空！");
                continue;
            }
            if (VERSION_MAP.get(module) == null ||
                    (!VERSION_MAP.get(module).equals(tDrlNversion.getVersion()))) {
                VERSION_MAP.put(module, tDrlNversion.getVersion());
                refreshRule(module);
            }
        }
    }

    /**
     * 加载指定类型的规则
     */
    public void refreshRule(String module) {
        log.info("开始加载[ " + module + " ]模块规则...");
        //根据模块加载所有的规则
        List<TDrlNSceneRuleBindConfig> ruleSet = generalRulesMapper.querySceneCodeRule(module);
        if (CollectionUtils.isEmpty(ruleSet)) {
            log.error("模块 {} 无对应规则！", module);
        } else {
            refresh(module, ruleSet);
        }
        log.info("[ " + module + " ]规则加载完成！");
    }

    /**
     * 重新加载给定模块给定规则列表，对应一个kie module
     *
     * @param module 模块id
     * @param list   规则列表
     */
    private void refresh(String module, List<TDrlNSceneRuleBindConfig> list) {
        Map<String, String> ruleNameMap = new HashMap<>();
        int count = 0;

        KieHelper kieHelper = new KieHelper();
        for (TDrlNSceneRuleBindConfig tDrlNSceneRuleBindConfig : list) {
            ruleNameMap.put("file" + count++ + ".drl", tDrlNSceneRuleBindConfig.getCode());
            log.info(module + " - " + tDrlNSceneRuleBindConfig.getCode());
            kieHelper.addContent(tDrlNSceneRuleBindConfig.getContent(), ResourceType.DRL);

        }
        //组装规则参数
        this.generalRulesBL.paramConfig(module, true);
        KieBase build = null;
        try {
            log.info("正在加载 " + module + " 模块的规则.....");
            build = kieHelper.build();
        } catch (Exception e) {
            log.info("模块" + module + "下的规则出错了：" + ruleNameMap.get(getRuleName(e)));
            log.error(e.getMessage(), e);
        }
        kieBaseConcurrentMap.put(buildKieHelperCode(module), build);
    }

    /**
     * 构建规则名称
     *
     * @param sceneCode
     * @return
     */
    private String buildKieHelperCode(String sceneCode) {
        return sceneCode.toLowerCase();
    }


    /**
     * 获取KieSession
     *
     * @param module 模块编码
     */
    public KieSession getKieSession(String module) {
        KieBase kieBase = this.kieBaseConcurrentMap.get(module.toLowerCase());
        if (kieBase == null) {
//            throw new RuntimeException("未找到该模块对应的规则集，模块编码：" + module);
            return null;
        }
        return kieBase.newKieSession();
    }

    /**
     * 获取StatelessKieSession
     *
     * @param module 模块编码
     * @return
     */
    public StatelessKieSession getStatelessKieSession(String module) {
        KieBase kieBase = this.kieBaseConcurrentMap.get(module.toLowerCase());
        if (kieBase == null) {
            throw new RuntimeException("未找到该模块对应的规则集，模块编码：" + module);
        }
        return kieBase.newStatelessKieSession();
    }

    private String getRuleName(Exception e) {
        if (e == null || e.getMessage() == null) {
            return "";
        }
        int i = e.getMessage().indexOf(".drl");
        int j = e.getMessage().indexOf("file");
        if (i == -1 || j == -1) {
            return "";
        }
        if (i <= j) {
            return "";
        }
        return e.getMessage().substring(j, i) + ".drl";
    }
}